/*
 * Copyright (c) 2001,2002
 *	Traakan, Inc., Los Altos, CA
 *	All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Project:  NDMJOB
 * Ident:    $Id: $
 *
 * Description:
 *
 */


#include "ndmlib.h"



int
ndmfhdb_add_file (struct ndmlog *ixlog, int tagc,
  char *raw_name, ndmp9_file_stat *fstat)
{
	char		prefix[8];
	char		statbuf[100];
	char		namebuf[NDMOS_CONST_PATH_MAX];

	strcpy (prefix, "DHf");
	prefix[0] = tagc;

	ndm_fstat_to_str (fstat, statbuf);

	ndmcstr_from_str (raw_name, namebuf, sizeof namebuf);

	ndmlogf (ixlog, prefix, 0, "%s UNIX %s", namebuf, statbuf);

	return 0;
}

int
ndmfhdb_add_dir (struct ndmlog *ixlog, int tagc,
  char *raw_name, ndmp9_u_quad dir_node, ndmp9_u_quad node)
{
	char		prefix[8];
	char		namebuf[NDMOS_CONST_PATH_MAX];

	strcpy (prefix, "DHd");
	prefix[0] = tagc;

	ndmcstr_from_str (raw_name, namebuf, sizeof namebuf);

	ndmlogf (ixlog, prefix, 0, "%llu %s UNIX %llu",
		dir_node, namebuf, node);

	return 0;
}

int
ndmfhdb_add_node (struct ndmlog *ixlog, int tagc,
  ndmp9_u_quad node, ndmp9_file_stat *fstat)
{
	char		prefix[8];
	char		statbuf[100];

	strcpy (prefix, "DHn");
	prefix[0] = tagc;

	ndm_fstat_to_str (fstat, statbuf);

	ndmlogf (ixlog, prefix, 0, "%llu UNIX %s", node, statbuf);

	return 0;
}

int
ndmfhdb_add_dirnode_root (struct ndmlog *ixlog, int tagc,
  ndmp9_u_quad root_node)
{
	char		prefix[8];

	strcpy (prefix, "DHr");
	prefix[0] = tagc;

	ndmlogf (ixlog, prefix, 0, "%llu", root_node);

	return 0;
}


int
ndmfhdb_add_fh_info_to_nlist (FILE *fp, ndmp9_name *nlist, int n_nlist)
{
	struct ndmfhdb		_fhcb, *fhcb = &_fhcb;
	int			i, rc, n_found;
	ndmp9_file_stat		fstat;

	rc = ndmfhdb_open (fp, fhcb);
	if (rc != 0) {
		return -31;
	}

	n_found = 0;

	for (i = 0; i < n_nlist; i++) {
		char *		name = nlist[i].original_path;

		rc = ndmfhdb_lookup (fhcb, name, &fstat);
		if (rc > 0) {
			nlist[i].fh_info = fstat.fh_info;
			if (fstat.fh_info.valid) {
				n_found++;
			}
		}
	}

	return n_found;
}

int
ndmfhdb_open (FILE *fp, struct ndmfhdb *fhcb)
{
	int		rc;

	NDMOS_MACRO_ZEROFILL (fhcb);

	fhcb->fp = fp;

	rc = ndmfhdb_dirnode_root (fhcb);
	if (rc > 0) {
		fhcb->use_dir_node = 1;
		return 0;
	}

	rc = ndmfhdb_file_root (fhcb);
	if (rc > 0) {
		fhcb->use_dir_node = 0;
		return 0;
	}

	return -1;
}

int
ndmfhdb_lookup (struct ndmfhdb *fhcb, char *path, ndmp9_file_stat *fstat)
{
	if (fhcb->use_dir_node) {
		return ndmfhdb_dirnode_lookup (fhcb, path, fstat);
	} else {
		return ndmfhdb_file_lookup (fhcb, path, fstat);
	}
}

int
ndmfhdb_dirnode_root (struct ndmfhdb *fhcb)
{
	int		rc, off;
	char *		p;
	char		key[256];
	char		linebuf[2048];

	sprintf (key, "DHr ");

	p = NDMOS_API_STREND(key);
	off = p - key;

	rc = ndmbstf_first (fhcb->fp, key, linebuf, sizeof linebuf);

	if (rc <= 0) {
		return rc;	/* error or not found */
	}

	fhcb->root_node = NDMOS_API_STRTOLL (linebuf+off, &p, 0);

	if (*p != 0) {
		return -10;
	}

	return 1;
}

int
ndmfhdb_dirnode_lookup (struct ndmfhdb *fhcb, char *path,
  ndmp9_file_stat *fstat)
{
	int			rc;
	char *			p;
	char *			q;
	char			component[256+128];
	unsigned long long	dir_node;
	unsigned long long	node;

	/* classic path name reduction */
	node = dir_node = fhcb->root_node;
	p = path;
	for (;;) {
		if (*p == '/') {
			p++;
			continue;
		}
		if (*p == 0) {
			break;
		}
		q = component;
		while (*p != 0 && *p != '/') {
			*q++ = *p++;
		}
		*q = 0;

		dir_node = node;
		rc = ndmfhdb_dir_lookup (fhcb, dir_node, component, &node);
		if (rc <= 0)
			return rc;	/* error or not found */
	}

	rc = ndmfhdb_node_lookup (fhcb, node, fstat);

	return rc;
}

int
ndmfhdb_dir_lookup (struct ndmfhdb *fhcb, unsigned long long dir_node,
  char *name, unsigned long long *node_p)
{
	int		rc, off;
	char *		p;
	char		key[256+128];
	char		linebuf[2048];

	sprintf (key, "DHd %llu ", dir_node);
	p = NDMOS_API_STREND(key);

	ndmcstr_from_str (name, p, sizeof key - (p-key) - 10);

	strcat (p, " UNIX ");

	p = NDMOS_API_STREND(key);
	off = p - key;

	rc = ndmbstf_first (fhcb->fp, key, linebuf, sizeof linebuf);

	if (rc <= 0) {
		return rc;	/* error or not found */
	}

	*node_p = NDMOS_API_STRTOLL (linebuf+off, &p, 0);

	if (*p != 0) {
		return -10;
	}

	return 1;
}

int
ndmfhdb_node_lookup (struct ndmfhdb *fhcb, unsigned long long node,
  ndmp9_file_stat *fstat)
{
	int		rc, off;
	char *		p;
	char		key[128];
	char		linebuf[2048];

	sprintf (key, "DHn %llu UNIX ", node);

	p = NDMOS_API_STREND(key);
	off = p - key;


	rc = ndmbstf_first (fhcb->fp, key, linebuf, sizeof linebuf);

	if (rc <= 0) {
		return rc;	/* error or not found */
	}


	rc = ndm_fstat_from_str (fstat, linebuf + off);
	if (rc < 0) {
		return rc;
	}

	return 1;
}

int
ndmfhdb_file_root (struct ndmfhdb *fhcb)
{
	int			rc;
	ndmp9_file_stat		fstat;

	rc = ndmfhdb_file_lookup (fhcb, "/", &fstat);
	if (rc > 0) {
		if (fstat.node.valid)
			fhcb->root_node = fstat.node.value;
	}

	return rc;
}

int
ndmfhdb_file_lookup (struct ndmfhdb *fhcb, char *path,
  ndmp9_file_stat *fstat)
{
	int		rc, off;
	char *		p;
	char		key[2048];
	char		linebuf[2048];

	sprintf (key, "DHf ");
	p = NDMOS_API_STREND(key);

	ndmcstr_from_str (path, p, sizeof key - (p-key) - 10);

	strcat (p, " UNIX ");

	p = NDMOS_API_STREND(key);
	off = p - key;

	rc = ndmbstf_first (fhcb->fp, key, linebuf, sizeof linebuf);

	if (rc <= 0) {
		return rc;	/* error or not found */
	}

	rc = ndm_fstat_from_str (fstat, linebuf + off);
	if (rc < 0) {
		return rc;
	}

	return 1;
}




/*
 * Same codes as wraplib.[ch] wrap_parse_fstat_subr()
 * and wrap_send_fstat_subr().
 */

char *
ndm_fstat_to_str (ndmp9_file_stat *fstat, char *buf)
{
	char *			p = buf;

	*p++ = 'f';
	switch (fstat->ftype) {
	case NDMP9_FILE_DIR:	*p++ = 'd';	break;
	case NDMP9_FILE_FIFO:	*p++ = 'p';	break;
	case NDMP9_FILE_CSPEC:	*p++ = 'c';	break;
	case NDMP9_FILE_BSPEC:	*p++ = 'b';	break;
	case NDMP9_FILE_REG:	*p++ = '-';	break;
	case NDMP9_FILE_SLINK:	*p++ = 'l';	break;
	case NDMP9_FILE_SOCK:	*p++ = 's';	break;
	case NDMP9_FILE_REGISTRY: *p++ = 'R';	break;
	case NDMP9_FILE_OTHER:	*p++ = 'o';	break;
	default:		*p++ = '?';	break;
	}
	*p = '\0';

	if (fstat->mode.valid) {
		sprintf (p, " m%04lo", fstat->mode.value & 07777);
	}
	while (*p) p++;

	if (fstat->uid.valid) {
		sprintf (p, " u%ld", fstat->uid.value);
	}
	while (*p) p++;

	if (fstat->gid.valid) {
		sprintf (p, " g%ld", fstat->gid.value);
	}
	while (*p) p++;

	if (fstat->ftype == NDMP9_FILE_REG
	 || fstat->ftype == NDMP9_FILE_SLINK) {
		if (fstat->size.valid) {
			sprintf (p, " s%llu", fstat->size.value);
		}
	} else {
		/* ignore size on other file types */
	}
	while (*p) p++;

	/* tar -t can not recover atime/ctime */
	/* they are also not particularly interesting in the index */

	if (fstat->mtime.valid) {
		sprintf (p, " tm%lu", fstat->mtime.value);
	}
	while (*p) p++;

	if (fstat->fh_info.valid) {
		sprintf (p, " @%lld", fstat->fh_info.value);
	}
	while (*p) p++;

	return buf;
}

int
ndm_fstat_from_str (ndmp9_file_stat *fstat, char *buf)
{
	char *			scan = buf;
	ndmp9_validity *	valid_p;

	NDMOS_MACRO_ZEROFILL (fstat);

	while (*scan) {
		char *		p = scan + 1;

		switch (*scan) {
		case ' ':
			scan++;
			continue;

		case '@':	/* fh_info */
			fstat->fh_info.value = NDMOS_API_STRTOLL (p, &scan, 0);
			valid_p = &fstat->fh_info.valid;
			break;

		case 's':	/* size */
			fstat->size.value = NDMOS_API_STRTOLL (p, &scan, 0);
			valid_p = &fstat->size.valid;
			break;

		case 'i':	/* fileno (inum) */
			fstat->node.value = NDMOS_API_STRTOLL (p, &scan, 0);
			valid_p = &fstat->node.valid;
			break;

		case 'm':	/* mode low twelve bits */
			fstat->mode.value = strtol (p, &scan, 8);
			valid_p = &fstat->mode.valid;
			break;

		case 'l':	/* link count */
			fstat->links.value = strtol (p, &scan, 0);
			valid_p = &fstat->links.valid;
			break;

		case 'u':	/* uid */
			fstat->uid.value = strtol (p, &scan, 0);
			valid_p = &fstat->uid.valid;
			break;

		case 'g':	/* gid */
			fstat->gid.value = strtol (p, &scan, 0);
			valid_p = &fstat->gid.valid;
			break;

		case 't':		/* one of the times */
			p = scan+2;
			switch (scan[1]) {
			case 'm':	/* mtime */
				fstat->mtime.value = strtol (p, &scan, 0);
				valid_p = &fstat->mtime.valid;
				break;

			case 'a':	/* atime */
				fstat->atime.value = strtol (p, &scan, 0);
				valid_p = &fstat->atime.valid;
				break;

			case 'c':	/* ctime */
				fstat->ctime.value = strtol (p, &scan, 0);
				valid_p = &fstat->ctime.valid;
				break;

			default:
				return -13;
			}
			break;

		case 'f':	/* ftype (file type) */
			switch (scan[1]) {
			case 'd': fstat->ftype = NDMP9_FILE_DIR; break;
			case 'p': fstat->ftype = NDMP9_FILE_FIFO; break;
			case 'c': fstat->ftype = NDMP9_FILE_CSPEC; break;
			case 'b': fstat->ftype = NDMP9_FILE_BSPEC; break;
			case '-': fstat->ftype = NDMP9_FILE_REG; break;
			case 'l': fstat->ftype = NDMP9_FILE_SLINK; break;
			case 's': fstat->ftype = NDMP9_FILE_SOCK; break;
			case 'R': fstat->ftype = NDMP9_FILE_REGISTRY; break;
			case 'o': fstat->ftype = NDMP9_FILE_OTHER; break;
			default:
				fstat->ftype = NDMP9_FILE_OTHER;
				return -15;
			}
			scan += 2;
			valid_p = 0;
			break;

		default:
			return -13;
		}

		if (*scan != ' ' && *scan != 0)
			return -11;

		if (valid_p)
			*valid_p = NDMP9_VALIDITY_VALID;
	}

	return 0;
}
